package c.c.k.service.impl;

import c.c.k.config.StockConfig;
import c.c.k.emums.JYSEnum;
import c.c.k.pojo.Event;
import c.c.k.pojo.Stock;
import c.c.k.pojo.StockBase;
import c.c.k.repository.EventRepository;
import c.c.k.repository.StockRepository;
import c.c.k.service.EventService;
import c.c.k.service.StockBaseService;
import c.c.k.service.StockService;
import c.c.k.util.StockData;
import c.c.k.util.StockUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by chenck on 2022/3/19.
 */
@Service
@Slf4j
public class StockServiceImpl implements StockService {
    private static final Date START_DATE = DateUtil.parseDate("2020-01-01");

    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private StockConfig stockConfig;
    @Autowired
    private StockBaseService stockBaseService;
    @Autowired
    private EventService eventService;

    @PostConstruct
    public void init(){
        new Thread(()->this.fetchEveryday()).start();
    }

    @Override
    public List<Stock> listStock(List<Long> ids) {
        return stockRepository.findAllById(ids);
    }

    @Override
    public List<Stock> listStock(JYSEnum jysEnum) {
        return stockRepository.findByJys(jysEnum.getDesc());
    }

    @Override
    public List<Stock> listStockByPercent(Integer minShizhi, Integer maxShiZhi, String jys) {
        Double min = minShizhi * 10000 * 10000D;
        Double max = maxShiZhi * 10000 * 10000D;
        return stockRepository.listStockByPercent(min, max, jys);
    }

    @Override
    public void addStock(Stock stock) {
        Stock one = stockRepository.findByCode(stock.getCode());
        if(one != null){
            return;
            //stock.setId(one.get().getId());
        }
        stockRepository.save(stock);
    }

    @Override
    public void updateStock(Long stockId, Double max, Double min) {
        Stock one = stockRepository.findById(stockId).get();
        one.setMaxPrice(max);
        one.setMinPrice(min);
        stockRepository.save(one);
    }

    @Override
    public void updateStock(Long stockId, Double nowPrice, Date nowDate, Double shiZhi) {
        Stock one = stockRepository.findById(stockId).get();

        Integer fromPercent = this.getPercent(one);
        if(nowDate.equals(one.getNowPriceDate()))
            throw new RuntimeException("已抓取");

        if(one.getMinPrice() > nowPrice){
            one.setMinPrice(nowPrice);
        }
        if(one.getMaxPrice() < nowPrice){
            one.setMaxPrice(nowPrice);
        }
        one.setPrePrice(one.getNowPrice());
        one.setNowPriceDate(nowDate);
        one.setNowPrice(nowPrice);
        one.setShiZhi(shiZhi);
        stockRepository.save(one);

        Integer toPercent = this.getPercent(one);
        if(this.skipTen(fromPercent, toPercent)) {
            eventService.addEvent(Event.builder()
                    .code(one.getCode())
                    .name(one.getName())
                    .date(DateUtil.beginOfDay(nowDate))
                    .stockId(stockId)
                    .jys(one.getJys())
                    .fromPercent(100 - fromPercent)
                    .toPercent(100 - toPercent)
                    .build());
        }
    }

    private boolean skipTen(Integer fromPercent, Integer toPercent){
        if(fromPercent  > toPercent) {
            return false;
        }

        for (int i = fromPercent + 1; i <= toPercent; i++) {
            if(i % 10 == 0)
                return true;
        }
        return false;
    }

    private Integer getPercent(Stock stock){
        return new Double(stock.getNowPrice() / stock.getMaxPrice() * 100).intValue();
    }

    @Override
    public void initMaxMin() {
        log.info("fetchHistory(JYSEnum.SH");
        this.initMaxMin(JYSEnum.SH, stockConfig.getTradeHistoryUrl());
        log.info("fetchHistory(JYSEnum.SZ");
        this.initMaxMin(JYSEnum.SZ, stockConfig.getTradeHistoryUrl());
        log.info("fetchHistory(JYSEnum.HK");
        this.initMaxMin(JYSEnum.HK, stockConfig.getTradeHistoryUrlHK());
        log.info("fetchHistory end......");
    }

    private void initMaxMin(JYSEnum jysEnum, String url){
        this.listStock(jysEnum).forEach(s->{
            try {
                if(s.getMaxPrice()>0)return;
                StockUtil.parseJsonArray(String.format(url, s.getCode()), objects->{
                    List<Double> list = new ArrayList<>();
                    for (int i = 0; i < objects.size(); i++) {
                        JSONObject jsonObject = objects.getJSONObject(i);
                        Date day = jsonObject.getDate("d");

                        if(day.before(START_DATE)){continue;}

                        list.add(jsonObject.getDouble("c"));
                    }
                    Double max = list.stream().max((a, b) -> new Double(a.floatValue() - b.floatValue()).intValue()).get();
                    int indexOf = list.indexOf(max);
                    Double min = list.subList(indexOf, list.size()).stream().min((a,b)->new Double(a.floatValue() - b.floatValue()).intValue()).get();
                    this.updateStock(s.getId(), max, min);
                });
            }catch (Exception ex){
                ex.printStackTrace();
            }
        });
    }

    @Override
    public void initStock() {
        /*StockData.map.forEach((k,v)->{
            String jys = k.substring(0,2);
            String code = k.substring(2);
            this.addStock(Stock.builder().code(code).name(v).jys(jys).maxPrice(0D).minPrice(0D).nowPrice(0D).shiZhi(0D).nowPriceDate(new Date(0)).build());
        });*/

        stockBaseService.listGtShiZhi(100D*10000*10000).forEach(s->{
            this.addStock(Stock.builder().id(s.getId()).code(s.getCode()).name(s.getName()).jys(s.getJys()).maxPrice(0D).minPrice(0D).nowPrice(0D).shiZhi(0D).nowPriceDate(new Date(0)).build());
        });
    }

    @Override
    public void fetchEveryday() {
        this.fetchEverydayByUrl(JYSEnum.SH, stockConfig.getTradeNowUrl());
        this.fetchEverydayByUrl(JYSEnum.SZ, stockConfig.getTradeNowUrl());
        this.fetchEverydayByUrl(JYSEnum.HK, stockConfig.getTradeNowUrlHK());
    }

    private  void fetchEverydayByUrl(JYSEnum jysEnum, String url){
        try {
            for (Stock stock : this.listStock(jysEnum)) {
                JSONObject jsonObject = JSONUtil.parseObj(HttpUtil.get(String.format(url, stock.getCode())));
                Double price = jsonObject.getDouble("p");
                Double shiZhi = jsonObject.getDouble("sz");
                Date nowDate = jsonObject.getDate("t");

                this.updateStock(stock.getId(), price, nowDate, shiZhi);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
